package edu.msg.jthr.backend.repository.beans;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceException;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;

import edu.msg.jthr.backend.model.AbstractModel;
import edu.msg.jthr.backend.repository.BaseRepository;
import edu.msg.jthr.backend.repository.RepositoryException;

public class BaseRepositoryBean<T extends AbstractModel, I> implements
		BaseRepository<T, I> {

	private final static String UNIT_NAME = "jthrdb";
	// private static final Logger LOG = LoggerFactory
	// .getLogger(BaseRepository.class);
	private final Class<T> clasz;

	@PersistenceContext(unitName = UNIT_NAME)
	protected EntityManager entityManager;

	public BaseRepositoryBean(Class<T> clasz) {
		this.clasz = clasz;
	}

	public EntityManager getEntityManager() {
		return entityManager;
	}

	@Override
	public void insert(T obj) throws RepositoryException {
		try {
			entityManager.persist(obj);
			// LOG.info("Insertion succeded");
		} catch (Exception e) {
			// LOG.error("Insertion failed - repository", e);
			throw new RepositoryException("Insertion failed - repository", e);
		}

	}

	@Override
	public void delete(T obj) throws RepositoryException {
		try {
			entityManager.remove(obj);
			// LOG.info("Deletion succeded");
		} catch (Exception e) {
			// LOG.error("Deletion failed - repository", e);
			throw new RepositoryException("Deletion failed - repository", e);
		}

	}

	@Override
	public T update(T obj) throws RepositoryException {
		try {
			T temp = entityManager.merge(obj);
			// LOG.info("Update succeded");
			return temp;
		} catch (Exception e) {
			// LOG.error("Update failed - repository", e);
			throw new RepositoryException("Update failed - repository", e);
		}

	}

	@Override
	public List<T> getAll() throws RepositoryException {
		try {
			final CriteriaBuilder cb = entityManager.getCriteriaBuilder();
			final CriteriaQuery<T> cq = cb.createQuery(clasz);
			final Root<T> root = cq.from(clasz);
			final CriteriaQuery<T> all = cq.select(root);
			final TypedQuery<T> tq = entityManager.createQuery(all);
			// LOG.info("GetAll succeded");
			return tq.getResultList();
		} catch (IllegalArgumentException | PersistenceException e) {
			// LOG.error("GetAll failed - repository", e);
			throw new RepositoryException("GetAll failed - repository", e);
		}
	}

	@Override
	public T getById(I id) throws RepositoryException {
		try {
			T temp = null;
			temp = entityManager.find(clasz, id);
			// LOG.info("GetById succeded");
			return temp;
		} catch (Exception e) {
			// LOG.error("GetById failed - repository", e);
			throw new RepositoryException("GetById failed - repository", e);
		}
	}

}
